#include "los_app.h"
#include "los_config.h"
#include "los_task.h"
#include "los_tick.h"
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>

#define MUSIC_TASK_STACK_SIZE 0x800
#define MUSIC_TASK_PRIORITY   20
#define TEMPO_BASE_MS         200U
#define REST_NOTE             0
#define NOTE_GAP_MS           40U

static volatile int g_buttonPressed = 0;
static UINT32 g_musicTaskId;

static const uint16_t g_tuneFreqs[] = {
    0,     /* silent/rest */
    4186,  /* C6   */
    4700,  /* D6   */
    5276,  /* E6   */
    5588,  /* F6   */
    6272,  /* G6   */
    7040,  /* A6   */
    7902,  /* B6   */
    3136,  /* G5   */
};

static const uint8_t g_scoreNotes[] = {
    1, 2, 3, 1,        1, 2, 3, 1,        3, 4, 5,  3, 4, 5,
    5, 6, 5, 4, 3, 1,  5, 6, 5, 4, 3, 1,  1, 8, 1,  1, 8, 1,
};

static const uint8_t g_scoreDurations[] = {
    4, 4, 4, 4,        4, 4, 4, 4,        4, 4, 8,  4, 4, 8,
    3, 1, 3, 1, 4, 4,  3, 1, 3, 1, 4, 4,  4, 4, 8,  4, 4, 8,
};

#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
typedef char MusicBoxScoreLengthCheck[(ARRAY_SIZE(g_scoreNotes) == ARRAY_SIZE(g_scoreDurations)) ? 1 : -1];

static const size_t g_totalNotes = ARRAY_SIZE(g_scoreNotes);

static VOID MusicBoxWaitIfPaused(VOID)
{
    while (g_buttonPressed != 0) {
        LOS_MDelay(50);
    }
}

static VOID MusicBoxPlayTone(uint8_t note, uint8_t durationUnits)
{
    const UINT32 durationMs = durationUnits * TEMPO_BASE_MS;

    if ((note >= (sizeof(g_tuneFreqs) / sizeof(g_tuneFreqs[0]))) || (note == REST_NOTE)) {
        printf("[MusicBox] Rest for %u ms\n", durationMs);
        LOS_MDelay(durationMs);
        return;
    }

    const uint16_t freq = g_tuneFreqs[note];
    printf("[MusicBox] Play note %u (approx. %u Hz) for %u ms\n", note, freq, durationMs);
    LOS_MDelay(durationMs);
    LOS_MDelay(NOTE_GAP_MS);
}

static VOID MusicBoxTaskEntry(UINT32 arg)
{
    (VOID)arg;

    printf("[MusicBox] Starting playback, tempo base %u ms per beat.\n", TEMPO_BASE_MS);

    while (1) {
        for (UINT32 i = 0; i < g_totalNotes; ++i) {
            MusicBoxWaitIfPaused();
            MusicBoxPlayTone(g_scoreNotes[i], g_scoreDurations[i]);
        }

        printf("[MusicBox] Song finished, looping...\n");
        LOS_MDelay(TEMPO_BASE_MS * 4); /* short pause before repeating */
    }
}

unsigned int LosAppInit(void)
{
    UINT32 ret;
    TSK_INIT_PARAM_S taskInit = {0};

    taskInit.pfnTaskEntry = (TSK_ENTRY_FUNC)MusicBoxTaskEntry;
    taskInit.uwStackSize = MUSIC_TASK_STACK_SIZE;
    taskInit.pcName = "music_box";
    taskInit.usTaskPrio = MUSIC_TASK_PRIORITY;

    ret = LOS_TaskCreate(&g_musicTaskId, &taskInit);
    if (ret != LOS_OK) {
        printf("[MusicBox] Failed to create task: 0x%x\n", ret);
        return ret;
    }

    printf("[MusicBox] Task created, id %u.\n", g_musicTaskId);
    return LOS_OK;
}
